﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static LightCAD.Three.Constants;


namespace LightCAD.Three
{
    public class RenderTargetOptions
    {
        public int mapping = 0;
        public int wrapS = 0;
        public int wrapT = 0;
        public int? magFilter = null;
        public int? minFilter = null;
        public int format = 0;
        public int type = 0;
        public int anisotropy = 0;
        public int encoding = 0;
        public bool? generateMipmaps = null;
        public string internalFormat = null;
        public bool depthBuffer = true;
        public bool stencilBuffer = false;
        public DepthTexture depthTexture = null;
        public int samples = -1;
    }
    public class WebGLRenderTarget : EventDispatcher, IImage, IDispose
    {

        public bool scissorTest;
        public Vector4 viewport;
        public Vector4 scissor;
        public readonly Image image;
        public bool depthBuffer;
        public bool stencilBuffer;
        public DepthTexture depthTexture;
        public int samples;
        public bool isXRRenderTarget;

        public JsArr<Texture> textures = new JsArr<Texture>();
        public Texture texture { get => textures[0]; set => textures[0] = value; }
        public int width { get; set; }
        public int height { get; set; }
        public int depth { get; set; }

        public WebGLRenderTarget(int width = 1, int height = 1, RenderTargetOptions options = null) : base()
        {
            if (options == null)
                options = new RenderTargetOptions();
            this.width = width;
            this.height = height;
            this.depth = 1;

            this.scissor = new Vector4(0, 0, width, height);
            this.scissorTest = false;

            this.viewport = new Vector4(0, 0, width, height);

            this.image = new Image { width = width, height = height, depth = 1 };

            this.texture = new Texture(image, options.mapping, options.wrapS, options.wrapT, options.magFilter ?? LinearFilter, options.minFilter ?? LinearMipmapLinearFilter, options.format, options.type, options.anisotropy, options.encoding);
            this.texture.isRenderTargetTexture = true;

            this.texture.flipY = false;
            this.texture.generateMipmaps = options.generateMipmaps ?? false;
            this.texture.internalFormat = options.internalFormat;
            this.texture.minFilter = options.minFilter ?? LinearFilter;

            this.depthBuffer = options.depthBuffer;
            this.stencilBuffer = options.stencilBuffer;

            this.depthTexture = options.depthTexture != null ? options.depthTexture : null;

            this.samples = options.samples != -1 ? options.samples : 0;
        }

        public virtual WebGLRenderTarget setSize(int width, int height, int depth = 1)
        {

            if (this.width != width || this.height != height || this.depth != depth)
            {

                this.width = width;
                this.height = height;
                this.depth = depth;

                this.texture.image.width = width;
                this.texture.image.height = height;
                this.texture.image.depth = depth;

                this.dispose();

            }

            this.viewport.set(0, 0, width, height);
            this.scissor.set(0, 0, width, height);
            return this;
        }

        public virtual WebGLRenderTarget clone()
        {

            return new WebGLRenderTarget().copy(this);

        }
        public virtual WebGLRenderTarget copy(WebGLRenderTarget source)
        {

            this.width = source.width;
            this.height = source.height;
            this.depth = source.depth;

            this.viewport.copy(source.viewport);

            this.texture = source.texture.clone();
            this.texture.isRenderTargetTexture = true;

            // ensure image object is not shared, see #20328

            var image = source.texture.image.cloneImage();
            this.texture.source = new Source(image);

            this.depthBuffer = source.depthBuffer;
            this.stencilBuffer = source.stencilBuffer;
            if (source.depthTexture != null) this.depthTexture = source.depthTexture.clone() as DepthTexture;
            this.samples = source.samples;

            return this;

        }

        public virtual void dispose()
        {

            this.dispatchEvent(new EventArgs { type = "dispose" });

        }

        public IImage cloneImage() => clone();
    }
}
